# -*- coding:utf-8 -*-
# @Time : 2020/10/20 18:06
# @Author: limeng
# @File : task_service.py
import os
import platform
import re
import subprocess

from application.libs import const
from application.libs.framework import *
from application.models.models import Addtask
from .add_task_operate_log import *


def file_upload(f, user_id):
    """
    文件上传
    :param f: 文件
    :param user_id: 用户
    :return:
    """
    way = ""
    if platform.system() == const.WINDOWS:
        way = const.UPLOAD_LOCAL_TEST_PATH
    elif platform.system() == const.LINUX:
        way = const.UPLOAD_LINUX_PATH
    flag = True
    try:
        upload_path = os.path.join(os.path.dirname(__file__), way, f.filename)  # 当前文件所在路径,secure_filename(f.filename)
        upload_path = os.path.abspath(upload_path)  # 将路径转换为绝对路径
        f.save(upload_path)
    except Exception as e:
        print({"message": "上传文件异常，%s" % e})
        flag = False
    task_operate_log("文件上传", "成功", f"计划任务脚本文件上传数据:上传文件绝对路径[{upload_path}]]", "未知id",
                     user_id, {}, {}, [])  # 日志记录
    return flag


def add_qa_task(data):
    """
    新增
    :param data: 操作人id/任务名称/cron
    :return: 布尔值
    """
    name = data["task_name"]
    cron = data["cron"]
    user_id = data["user_id"]
    rep_if = if_task(name)
    if rep_if:
        error_olog(f"新增的任务名称{name}已存在", "新增", rep_if.id, user_id, {}, {}, [])
        return False
    else:  # 新增
        add_task = Addtask()
        add_task.task_name = name
        add_task.begin_time = cron
        add_task.add_time = time.strftime(
            "%Y-%m-%d %H:%M:%S",
            time.localtime())
        add_task.type = 0
        try:
            db.session.add(add_task)
            db.session.commit()
            rep_if = if_task(name)
            operate_now_dic = {"task_name": rep_if.task_name, "begin_time": rep_if.begin_time,
                               "add_time": rep_if.add_time, "type": rep_if.type}
            operate_old_dic = {"task_name": "", "begin_time": "",
                               "add_time": "", "type": ""}
            task_operate_log("添加", "成功",
                             f"新增计划任务数据:[id={rep_if.id},任务名称：{rep_if.task_name},cron:{rep_if.begin_time},创建时间：{rep_if.add_time},任务状态：{rep_if.type}]",
                             rep_if.id, user_id, operate_old_dic, operate_now_dic,
                             operate_now_dic.keys())  # 日志记录
            # db.session.close()
            return True
        except Exception as e:
            db.session.rollback()  # 添加失败不计入计划任务列表的操作日志，关联不上计划任务id
            error_olog(e, "新增", rep_if.id, user_id, {}, {}, [])
            return False


def if_task(name):
    """
    判断新增数据是否存在
    :param name:任务名称
    :return: 一个Addtask实体
    """
    return db.session.query(Addtask).filter(Addtask.task_name == name).first()


def sel_task(data):
    """
    查询
    :return: dict
    """
    page_num = data[const.PAGE_NUM]
    page_per = data[const.PAGE_PER]
    page_data = db.session.query(Addtask).paginate(page=page_num, per_page=page_per, error_out=False)
    response_task_dic = {}
    response_case_list = []
    if page_data.items:
        for msg in page_data.items:
            response_task_dic['id'] = msg.id
            response_task_dic['task_name'] = msg.task_name
            response_task_dic['begin_time'] = msg.begin_time
            response_task_dic['add_time'] = msg.add_time
            response_task_dic['type'] = msg.type
            response_case_list.append(response_task_dic.copy())
            response_task_dic.clear()
    response_task_dic['items'] = response_case_list
    response_task_dic['total'] = page_data.total
    return response_task_dic


def del_task(data):
    """
    删除
    :param data: 操作人id/任务id
    :return:
    """
    id = data["task_id"]
    user_id = data["user_id"]
    # 物理删除
    rep = db.session.query(Addtask).filter(Addtask.id == id).first()
    if rep.type == 0:
        del_task = db.session.query(Addtask).filter(Addtask.id == id).first()
        try:
            db.session.delete(del_task)
            # 日志记录
            task_operate_log("删除", "成功",
                             f"删除计划任务数据[id={rep.id},任务名称：{rep.task_name},cron:{rep.begin_time},创建时间：{rep.add_time},任务状态：{rep.type}]",
                             id, user_id, {}, {}, [])
            return True
        except Exception as e:
            db.session.rollback()
            error_olog(e, "删除", id, user_id, {}, {}, [])
            return False
    else:
        return False


def edit_task(data):
    """
    修改
    :param data: user_id: 操作人id,id: 任务id,name: 任务名称,content: 执行时间内容 cron
    :return: 布尔值
    """
    id = data["id"]
    name = data["task_name"]
    cron = data["begin_time"]
    user_id = data["user_id"]
    rep_if = db.session.query(Addtask).filter(Addtask.id == id).first()
    if rep_if:
        if name and cron:
            operate_now_dic = {}
            operate_old_dic = {}
            if rep_if.task_name != name:
                operate_now_dic["task_name"] = name
                operate_old_dic["task_name"] = rep_if.task_name
            if rep_if.begin_time != cron:
                operate_now_dic["begin_time"] = cron
                operate_old_dic["begin_time"] = rep_if.begin_time
            if operate_now_dic == {}:
                error_olog("名称,cron值未发生变化，无需修改", "修改", rep_if.id, user_id, {}, {}, [])
                return False
            db.session.query(Addtask).filter(Addtask.id == rep_if.id).update(operate_now_dic)
            try:
                db.session.commit()
                # 日志记录
                up_task = db.session.query(Addtask).filter(Addtask.id == rep_if.id).first()
                task_operate_log("修改", "成功",
                                 f"修改前数据:[id={rep_if.id},任务名称：{rep_if.task_name},cron:{rep_if.begin_time}],"
                                 f"已更改为[id={up_task.id},任务名称：{up_task.task_name},"
                                 f"cron:{up_task.begin_time}]",
                                 up_task.id, user_id, operate_old_dic, operate_now_dic,
                                 operate_now_dic.keys())  # 日志记录
                # db.session.close()
                return True
            except Exception as e:
                db.session.rollback()
                error_olog(e, "修改", rep_if.id, user_id, {}, {}, [])
                return False
        else:
            error_olog("名称,cron不可为空", "修改", rep_if.id, user_id, {}, {}, [])
            return False
    else:
        error_olog(f"名称为{name},cron为{rep_if.begin_time}的计划任务不存在", "修改", rep_if.id, user_id, {}, {}, [])
        return False


def error_olog(e, err_type, task_id, user_id, operate_old_dic, operate_now_dic, operate_fields):
    """
    异常日志记录
    :param user_id: 用户id
    :param task_id:计划任务id
    :param err_type: 错误类型
    :param e: Exception
    """
    task_operate_log(err_type, "失败", f"捕获异常:{e}", task_id, user_id, operate_old_dic,
                     operate_now_dic, operate_fields)


def ttask_add(id, task_cron, user_id):
    """
    linux定时执行任务文件中添加cron
    :param user_id:
    :param id:
    :param task_cron:cron
    :return: 布尔
    """
    # 本地测试地址：win>>>E:/a.txt & linux>>>/var/spool/cron/root
    with open(const.UPLOAD_LINUX_CRON_PATH, "r", encoding=const.UTF_8) as f:
        lines = f.readlines()
    with open(const.UPLOAD_LINUX_CRON_PATH, "a", encoding=const.UTF_8) as f_w:
        for line in lines:
            if task_cron in line:
                # 日志记录
                error_olog(f"cron数据[{task_cron}]]任务已存在", "修改", id, user_id, {}, {}, [])
                return False
        f_w.write(task_cron + '\n')
    f_w.close()
    f.close()
    # 日志记录
    with open(const.UPLOAD_LINUX_CRON_PATH, "r", encoding=const.UTF_8) as f:
        now_lines = f.readlines()
    task_operate_log("linux添加cron", "成功", f"添加的cron数据为[{task_cron}]", id, user_id,
                     {"linux定时任务文件": str(lines)}, {"linux定时任务文件": str(now_lines)},
                     ['linux定时任务文件'])
    return True


def ttask_del(id, task_cron, user_id):
    """
    linux定时执行任务文件中删除cron
    :param id: id
    :param task_cron: 执行时机
    :param user_id:用户id
    :return: 布尔
    """
    flag = 0  # 删除标识
    with open(const.UPLOAD_LINUX_CRON_PATH, "r", encoding=const.UTF_8) as f:
        lines = f.readlines()
    with open(const.UPLOAD_LINUX_CRON_PATH, "w", encoding=const.UTF_8) as f_w:
        for line in lines:
            if task_cron in line:
                flag = 1
                continue
            f_w.write(line)
    f_w.close()
    f.close()
    if flag == 0:
        return False
    # 日志记录
    with open(const.UPLOAD_LINUX_CRON_PATH, "r", encoding=const.UTF_8) as f:
        now_lines = f.readlines()
    task_operate_log("linux删除cron", "成功", f"cron数据[{task_cron}]]", id, user_id,
                     {"linux定时任务文件": str(lines)}, {"linux定时任务文件": str(now_lines)},
                     ["linux定时任务文件"])
    return True


def task_run(data):
    """
    执行任务
    :param data: user_id: 操作人id status:状态》》1启动0停止 task_cron:cron id:操作人id
    :return: 字符串
    """
    if platform.system() == const.WINDOWS:
        return result(const.FAIL_50000, "请在linux环境部署项目后在进行操作！", None)
    id = data['task_id']
    user_id = data["user_id"]
    is_task = db.session.query(Addtask).filter(Addtask.id == id).first()
    if is_task:
        cron = regular_matching_cron(is_task.begin_time)  # 截取
        req_str = const.TASK_EXECUTE_FAIL
        try:
            r_c = subprocess.run(cron, shell=True)
            if r_c.returncode == 0:
                req_str = const.TASK_EXECUTE_SUCCESS
        except:
            req_str = const.TASK_EXECUTE_FAIL
        try:
            # 日志记录
            task_operate_log("执行任务", req_str,
                             f"计划任务数据[[id={is_task.id},任务名称：{is_task.task_name},cron:{is_task.begin_time}]]{req_str}",
                             id, user_id, {}, {}, [])
            db.session.commit()
            if req_str == const.TASK_EXECUTE_SUCCESS:
                return result(const.SUCCESS, req_str, None)
            else:
                return result(const.FAIL_50000, req_str, None)
        except:
            db.session.rollback()
            return result(const.FAIL_50000, const.OPERATE_FAIL, None)
    else:
        return result(const.FAIL_50000, "计划任务不存在", None)


def run_stop_task(data):
    """
    启动停止任务
    :param data: user_id: 操作人id status:状态》》1启动0停止 task_cron:cron id:操作人id
    :return: 字符串
    """
    if platform.system() == const.WINDOWS:
        return result(const.FAIL_50000, "请在linux环境部署项目后在进行操作！", None)
    status = data["status"]
    id = data['task_id']
    user_id = data["user_id"]
    is_task = db.session.query(Addtask).filter(Addtask.id == id).first()
    if is_task:
        operate_old_dic = {"type": is_task.type}
        if status == 1:
            if ttask_add(id, is_task.begin_time, user_id):
                req_str = const.TASK_START_SUCCESS
            else:
                req_str = const.TASK_START_FAIL
        elif status == 0:
            if ttask_del(id, is_task.begin_time, user_id):
                req_str = const.TASK_STOP_SUCCESS
            else:
                req_str = const.TASK_STOP_FAIL
        else:
            return result(const.FAIL_50000, "任务状态不符合逻辑", None)
        db.session.query(Addtask).filter(Addtask.id == id).update({"type": status})
        is_task2 = db.session.query(Addtask).filter(Addtask.id == id).first()
        try:
            # 日志记录
            operate_now_dic = {"type": is_task2.type}
            task_operate_log("启动/停止任务", req_str,
                             f"计划任务数据[[id={is_task2.id},任务名称：{is_task2.task_name},cron:{is_task2.begin_time}]]{req_str}",
                             id, user_id, operate_old_dic, operate_now_dic,
                             operate_now_dic.keys())
            db.session.commit()
            # db.session.close()
            return result(const.SUCCESS, req_str, None)
        except:
            db.session.rollback()
            return result(const.FAIL_50000, "操作失败", None)
    else:
        return result(const.FAIL_50000, "计划任务不存在", None)


def regular_matching_cron(cron):
    """
    截取执行命令
    :param cron: 包含执行时间的命令
    :return: 截取后的cron
    """
    s_cron = re.search("cd.*\.log", cron).group()
    return s_cron
